package com.kwan.xframe.mvvm;

import android.text.TextUtils;

import com.kwan.xframe.mvvm.data.source.http.exception.TokenExpireException;
import com.kwan.xframe.mvvm.data.source.http.exception.TokenNotValidThrowable;

import org.reactivestreams.Publisher;

import java.util.concurrent.atomic.AtomicBoolean;

import io.reactivex.rxjava3.core.BackpressureStrategy;
import io.reactivex.rxjava3.core.Flowable;
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.core.ObservableSource;
import io.reactivex.rxjava3.functions.Function;
import io.reactivex.rxjava3.functions.Supplier;
import io.reactivex.rxjava3.subjects.PublishSubject;
import timber.log.Timber;

public abstract class BaseTokenManager {

	public static String sToken = "";
	public static boolean isTokenExpire = false;
	private final AtomicBoolean mRefreshing = new AtomicBoolean(false);
	private PublishSubject<String> mPublishSubject;
	private final Observable<String> mTokenObservable;

	/**
	 * 获取Token的被观察者
	 *
	 * @return token 来源
	 */
	public abstract Observable<String> fetchTokenObservable();

	public BaseTokenManager() {

		mTokenObservable = fetchTokenObservable()
				.retryWhen(new Function<Observable<Throwable>, ObservableSource<?>>() {

					private int retryCount = 0;

					@Override
					public ObservableSource<?> apply(Observable<Throwable> throwableFlowable) throws Throwable {
						return throwableFlowable.flatMap(new Function<Throwable, ObservableSource<?>>() {
							@Override
							public ObservableSource<?> apply(Throwable throwable) throws Throwable {
								retryCount++;
								Timber.e("retryCount:"+retryCount+" throwable"+throwable);
								if (retryCount == 3) {
									//失败次数达到阈值，更改请求策略
									//request.setFlag(0);
									Timber.e("失败次数达到阈值，更改请求策略");
									return Observable.just("获取token失败重试次数超过3次");
								} else if (retryCount > 3) {
									//失败次数超过阈值，抛出失败，放弃请求
									mRefreshing.set(false);
									Timber.e("失败次数超过阈值，抛出失败，放弃请求");
									return Observable.error(throwable);
								} else {
									//再次请求token
									Timber.e("再次请求token");
									mRefreshing.set(false);
									return getNetTokenLocked();
								}
							}
						});
					}
				}).map(new Function<String, String>() {
					@Override
					public String apply(String result) throws Throwable {
						Timber.e("刷新token... %s", result);
						//http 本地token
						setCacheToken(result);
						//请求完成标识
						mRefreshing.set(false);
						return result;
					}
				});
	}

	public abstract void onFreshToken(String token);

	public String getCacheToken() {
		return sToken;
	}

	public void setCacheToken(String token) {
		onFreshToken(token);
		sToken = token;
		isTokenExpire = false;
	}

	public Observable<String> getNetTokenLocked() {

		boolean b = mRefreshing.compareAndSet(false, true);
		//boolean b = mRefreshing.compareAndSet(true, true);
		Timber.e("getNetTokenLocked :"+b);
		if (b) {

			Timber.e("没有请求，发起一次新的Token请求");
			startTokenRequest();
		} else {
			Timber.e("已经有请求，直接返回等待");
		}

		return mPublishSubject;
	}

	private void startTokenRequest() {
		mPublishSubject = PublishSubject.create();
		mTokenObservable.subscribe(mPublishSubject);
	}


	/**
	 * 处理token
	 *
	 * @param apiFlowable
	 * @param <T>
	 * @return
	 */


	public <T> Flowable<T> handleToken(Flowable<T> apiFlowable) {
		Timber.e("handleToken.............");
		return Flowable
				.defer(new Supplier<Publisher<String>>() {
					@Override
					public Flowable<String> get() throws Throwable {
						Timber.e("defer : %s", sToken);
						return Flowable.just(sToken);
					}
				})
				.flatMap(new Function<String, Flowable<T>>() {
					@Override
					public Flowable<T> apply(String token) throws Throwable {
						Timber.e("调用API 检测本地 token : %s", token);
						if (TextUtils.isEmpty(token)) {
							//token没有缓存，需要请求Token
							Timber.e("本地 token没有缓存，需要请求Token ");
							return Flowable.error(new TokenNotValidThrowable("本地无效token"));
						} else if (isTokenExpire) {
							Timber.e("token没有缓存，需要请求Token ");
							return Flowable.error(new TokenExpireException("缓存过期了"));
						} else {
							//Token存在缓存，直接请求
							Timber.e("Token 存在缓存 且 没有过期，直接请求.....");
							return apiFlowable;
						}
					}
				})
				.retryWhen(new Function<Flowable<Throwable>, Flowable<?>>() {//token失效重试;

					private int retryCount = 0;

					@Override
					public Flowable<?> apply(Flowable<Throwable> throwableFlowable) throws Throwable {

						return throwableFlowable.flatMap(new Function<Throwable, Flowable<?>>() {
							@Override
							public Flowable<?> apply(Throwable throwable) throws Throwable {

								if (throwable instanceof TokenNotValidThrowable ||
										throwable instanceof TokenExpireException) {

									Timber.e("handleTokenException # 捕获  %s", throwable.getClass().getSimpleName());
									Timber.e("retryCount : " + retryCount);

									if (throwable instanceof TokenExpireException) {
										isTokenExpire = true;
									}

									if (retryCount > 0) {
										Timber.e("handleTokenException # 同一Request，有过一次 , 则不再重试 ");
										return Flowable.error(throwable);
									} else {
										Timber.e("handleTokenException # token 缓存不在，请求token ");
										retryCount++;
										return getNetTokenLocked().toFlowable(BackpressureStrategy.BUFFER);
									}
								}
								return Flowable.error(throwable);
							}
						});
					}
				});
	}


}
